import java.awt.*;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.*;
import static java.lang.System.out;  //debugging

/** Class Court */
//public class Court extends JPanel implements MouseListener, MouseMotionListener {
public class Court extends JPanel {
	private Color bgColor, courtColor, lineColor;
        private int height, width;
	private Vector<Player> players;
        private boolean showNames=true, showRoles=true;
        private Formation teamFormation = Formation.FORMATION_4_2;
        private StartingFormation teamStartingFormation = StartingFormation.NO_FORMATION;
        
        // Default Server location
        private final Location SERVER_DEFAULT_LOCATION = new Location(50, 425);
        
        // Default formation locations
        private final Location FRONT_LEFT_DEFAULT_LOCATION = new Location(400, 150);
        private final Location FRONT_CENTER_DEFAULT_LOCATION = new Location(500, 275);
        private final Location FRONT_RIGHT_DEFAULT_LOCATION = new Location(400, 425);
        private final Location BACK_LEFT_DEFAULT_LOCATION = new Location(200, 150);
        private final Location BACK_CENTER_DEFAULT_LOCATION = new Location(300, 275);
        private final Location BACK_RIGHT_DEFAULT_LOCATION = new Location(200, 425);
        
        /** Class Location */
        public static class Location {
            public int x=0;
            public int y=0;
            
            public Location(){}
            public Location(int argX, int argY){
                this.x = argX;
                this.y = argY;
            }
        }
        
        /** Enum Formation */
        public enum Formation {
            FORMATION_6_2, FORMATION_4_2, FORMATION_5_1
        }
        
        /** Enum Formation */
        public enum StartingFormation {
            FORMATION_RECEIVE_SERVE, FORMATION_TEAM_SERVE, NO_FORMATION
        }

        /** Constructor */
	public Court () {
            this.setLayout(new BorderLayout());
            setBackgroundColor(new Color(100,149,237));
            setCourtColor(new Color(218,165,32));
            setLineColor(Color.black);
            players = new Vector<Player>();
            players.removeAllElements();
            //addMouseListener(this);
	}
	
        /** setBackgroundColor */
	public void setBackgroundColor(Color color) {
            bgColor = color;
            this.setBackground(bgColor);
            repaint();
	}
	
        /** getBackgroundColor */
	public Color getBackgroundColor() {return bgColor;}
	
        /** setCourtColor */
	public void setCourtColor(Color color) {
            courtColor = color;
            repaint();
	}
	
        /** getCourtColor */
	public Color getCourtColor() {return courtColor;}
	
        /** setLineColor */
	public void setLineColor(Color color) {
            lineColor = color;
            repaint();
	}
	
        /** getLineColor */
	public Color getLineColor() {return lineColor;}
        
        /** setShowNamesAttribute */
        public void setShowNamesAttribute(boolean flag){
            showNames = flag;
            repaint();
        }
        
        /** setShowRolesAttribute */
        public void setShowRolesAttribute(boolean flag){
            showRoles = flag;
            repaint();
        }
        
        /** setTeamFormation */
	public void setTeamFormation(Formation form) {
            this.teamFormation = form;
            
            // set roles of players base on 4-2 formation
            if (this.teamFormation == Formation.FORMATION_4_2){
                for (Player player : players) {
                    // power hitter in front row
                    if(player.getRole() == Player.Role.POWER_HITTER && 
                       !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.POWER_HITTER);
                    }
                    // setter in front row
                    else if(player.getRole() == Player.Role.SETTER && 
                       !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.SETTER);
                    }
                    // weak side hitter in front row
                    else if(player.getRole() == Player.Role.WEAKSIDE_HITTER && 
                       !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.WEAKSIDE_HITTER);
                    }
                    // player in back row
                    else if(player.inBackRow()) {
                        player.setCurrentRole(Player.Role.DEFENDER);
                    }
                }
            }
            // set roles of players base on 6-2 formation
            else if (this.teamFormation == Formation.FORMATION_6_2){
                for (Player player : players) {
                    // power hitter in front row
                    if(player.getRole() == Player.Role.POWER_HITTER && 
                       !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.POWER_HITTER);
                    }
                    // setter in front row
                    else if(player.getRole() == Player.Role.SETTER && 
                            !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.WEAKSIDE_HITTER);
                    }
                    // setter in back row
                    else if(player.getRole() == Player.Role.SETTER && 
                            player.inBackRow()) {
                        player.setCurrentRole(Player.Role.SETTER);
                    }
                    // mid-blocker in front row
                    else if(player.getRole() == Player.Role.MID_BLOCKER && 
                            player.inBackRow()) {
                        player.setCurrentRole(Player.Role.MID_BLOCKER);
                    }
                    // weak-side hitter in front in front row
                    // (set to mid-blocker for now)
                    else if(player.getRole() == Player.Role.WEAKSIDE_HITTER && 
                            !player.inBackRow()) {
                        player.setCurrentRole(Player.Role.MID_BLOCKER);
                    }
                    // player in back row
                    else if(player.inBackRow()) {
                            player.setCurrentRole(Player.Role.DEFENDER);
                    }
                }
            }
	}
	
        /** getTeamFormation */
	public Formation getTeamFormation() {return teamFormation;}
        
        /** setStartingTeamFormation */
	public void setStartingTeamFormation(StartingFormation formation) {
            StartingFormation oldForm = teamStartingFormation;
            teamStartingFormation = formation;
            
            if(teamStartingFormation != oldForm) {
                movePlayersStartingFormation();
            }
        }
        
        /** setStartingTeamFormation */
	public Player getPlayer(Player.Position pos) {
            Player temp = new Player();
            // search players for one in provided position
            for (Player player : players) {
                if(player.getPosition() == pos) {
                     return player; // return player object if in provided position
                }
            }
            return temp; // return empty player object if not found player
        }
        
        /** paintComponent */
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            height = this.getHeight();
            width = this.getWidth();
            g.setFont(new Font( "SansSerif", Font.BOLD, 12 ));
            g.setColor(getCourtColor());
            g.fillRect(100, 100, width - 200, height - 200);
            g.setColor(getLineColor());
            g.drawRect(100, 100, width - 200, height - 200);  //draw Rectangle
            g.drawLine(width/2, 100, width/2, height - 100);  //draw center line
            g.drawLine(width/2 - 150, 100, width/2 - 150, height - 100);  //draw 10" line
            g.drawLine(width/2 + 150, 100, width/2 + 150, height - 100);  //draw other 10" line
     
            //display players
            for (Player player : players) {
                try {
                    java.net.URL imgURL = player.getImgUrl();
                    if (imgURL != null) {
                        BufferedImage img = ImageIO.read(imgURL);
                        //draw player image onto the court
                        g.drawImage(img, player.getXPos(), player.getYPos(), 
                                    player.getPlayerImageWidth(), 
                                    player.getPlayerImageHeight(), null);
                        if(showNames){
                            //draw player's name to top left of player image
                            g.drawString(player.getName(),
                                         player.getXPos(), 
                                         player.getYPos());
                        }
                        if(showRoles){
                            //draw player's position to bottom left of player image
                            g.drawString(player.getCurrentRole().toString(), 
                                         player.getXPos(), 
                                         player.getYPos()+player.getPlayerImageHeight()+5);
                        }
                        repaint();
                    }
                    else {
                        //draw player's name and position instead of image
                        //cannot move the player in this case
                        //TODO: Consider a default image file to use for this case
                        g.drawString(player.getName(), player.getXPos(), player.getYPos());
                        g.drawString(player.getPosition().toString(), 
                                     player.getXPos(), 
                                     player.getYPos()+20);
                    }  
                }
                catch (IOException e){ e.printStackTrace(); }
            }
            
	} //end paintComponent
        
        /** addPlayer */
        public void addPlayer(String loc, int x, int y, Player.Position pos) {
            //add player
            players.add(new Player(loc, x, y, pos));
            this.addMouseListener(players.lastElement());
            this.addMouseMotionListener(players.lastElement());
            
            Thread t = new Thread(players.lastElement());
            t.start();
            
            repaint();
	}
        
        /** addPlayer */
        public void addPlayer(String loc, int x, int y, Player.Height height,
                              Player.Position pos) {
            //add player
            players.add(new Player(loc, x, y, height, pos));
            this.addMouseListener(players.lastElement());
            this.addMouseMotionListener(players.lastElement());
            
            Thread t = new Thread(players.lastElement());
            t.start();
            repaint();
	}
        
        /** addPlayer */
        public void addPlayer(String loc, int x, int y, String name,
                              Player.Height height, 
                              Player.Position pos,
                              Player.Role role) {
            //add player
            players.add(new Player(loc, x, y, name, height, pos, role));
            this.addMouseListener(players.lastElement());
            this.addMouseMotionListener(players.lastElement());
            
            Thread t = new Thread(players.lastElement());
            t.start();
            repaint();
	}
        
        /** movePlayersStartingFormation */
        public void movePlayersStartingFormation(){
           Location frontCenterLoc  = new Location(FRONT_CENTER_DEFAULT_LOCATION.x, 
                                                   FRONT_CENTER_DEFAULT_LOCATION.y), 
                    frontLeftLoc    = new Location(FRONT_LEFT_DEFAULT_LOCATION.x, 
                                                   FRONT_LEFT_DEFAULT_LOCATION.y), 
                    frontRightLoc   = new Location(FRONT_RIGHT_DEFAULT_LOCATION.x, 
                                                   FRONT_RIGHT_DEFAULT_LOCATION.y), 
                    backCenterLoc   = new Location(BACK_CENTER_DEFAULT_LOCATION.x, 
                                                   BACK_CENTER_DEFAULT_LOCATION.y), 
                    backLeftLoc     = new Location(BACK_LEFT_DEFAULT_LOCATION.x, 
                                                   BACK_LEFT_DEFAULT_LOCATION.y), 
                    backRightLoc    = new Location(BACK_RIGHT_DEFAULT_LOCATION.x, 
                                                   BACK_RIGHT_DEFAULT_LOCATION.y);

            if (teamFormation == Formation.FORMATION_4_2) {
                for (Player player : players) {
                    switch(player.getPosition())
                    {
                        case FRONT_CENTER:
                            if(player.getCurrentRole() == Player.Role.SETTER) {
                                // setter in center; stay in current location
                                player.setPlayerLocation(frontCenterLoc);
                            }
                            else if(player.getCurrentRole() == Player.Role.POWER_HITTER) {
                                // move power hitter back if in default center location
                                if( player.inLocation(FRONT_CENTER_DEFAULT_LOCATION) ) {
                                    // move power hitter back 
                                    frontCenterLoc.x -= 100;
                                    frontCenterLoc.y += 50;
                                    player.setPlayerLocation(frontCenterLoc);
                                } 
                            }
                            else if(player.getCurrentRole() == Player.Role.WEAKSIDE_HITTER) {
                                // move weak hitter back if in default center location
                                if( player.inLocation(FRONT_CENTER_DEFAULT_LOCATION) ) {
                                    // move weak hitter back
                                    frontCenterLoc.x -= 100;
                                    frontCenterLoc.y -= 50;
                                    player.setPlayerLocation(frontCenterLoc);
                                }  
                            }
                            // move other players to default center location
                            else{player.setPlayerLocation(frontCenterLoc);}
                            break;
                        case FRONT_LEFT: 
                            if(player.getCurrentRole() == Player.Role.SETTER) {
                                // move setter up to net if in default left location
                                if( player.inLocation(FRONT_LEFT_DEFAULT_LOCATION) ) {
                                    frontLeftLoc.x += 100;
                                    player.setPlayerLocation(frontLeftLoc);
                                }
                            }
                            break;
                        case FRONT_RIGHT: 
                            // move setter up to net if in default right location
                            if(player.getCurrentRole() == Player.Role.SETTER) {
                                if( player.inLocation(FRONT_RIGHT_DEFAULT_LOCATION) ) {
                                    frontRightLoc.x += 100;
                                    player.setPlayerLocation(frontRightLoc);
                                }
                            }
                            break;
                        case BACK_CENTER: 
                            player.setPlayerLocation(backCenterLoc);
                            break;
                        case BACK_LEFT: 
                            player.setPlayerLocation(backLeftLoc);
                            break;
                        case BACK_RIGHT:
                            if (teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE) {
                                player.setPlayerLocation(SERVER_DEFAULT_LOCATION);
                            } else { 
                                player.setPlayerLocation(backRightLoc);
                            }
                            break;
                        default:  break;
                    }
                }
            } // end else if (teamFormation == Formation.FORMATION_4_2)
            else if (teamFormation == Formation.FORMATION_6_2) { 
                for (Player player : players) {
                    switch(player.getPosition())
                    {
                        case FRONT_CENTER:
                            if( player.getCurrentRole() == Player.Role.MID_BLOCKER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontCenterLoc.x  -= 50;
                                player.setPlayerLocation(frontCenterLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.WEAKSIDE_HITTER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontCenterLoc.x  -= 75;
                                frontCenterLoc.y  += 75;
                                player.setPlayerLocation(frontCenterLoc);
                            }
                            else if( teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE && 
                                     getPlayer(Player.Position.BACK_CENTER).getCurrentRole() != Player.Role.SETTER) {
                                frontCenterLoc.x  -= 150;
                                player.setPlayerLocation(frontCenterLoc);
                            }
                            else { player.setPlayerLocation(frontCenterLoc); }
                            break;
                        case FRONT_LEFT: 
                            if( player.getCurrentRole() == Player.Role.MID_BLOCKER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontLeftLoc.x  += 100;
                                frontLeftLoc.y  += 40;
                                player.setPlayerLocation(frontLeftLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.WEAKSIDE_HITTER && 
                                     teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontLeftLoc.y  += 100;
                                player.setPlayerLocation(frontLeftLoc);
                            }
                            else if( teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE &&
                                     getPlayer(Player.Position.BACK_LEFT).getCurrentRole() == Player.Role.SETTER ) {
                                frontLeftLoc.x  += 100;
                                player.setPlayerLocation(frontLeftLoc);
                            }
                            else if( teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                if (getPlayer(Player.Position.BACK_CENTER).getCurrentRole() == Player.Role.SETTER) {
                                    frontLeftLoc.x  -= 50;
                                } else { frontLeftLoc.x  -= 150; }
                                player.setPlayerLocation(frontLeftLoc);
                            }
                            else { player.setPlayerLocation(frontLeftLoc); }
                            break;
                        case FRONT_RIGHT: 
                            if( player.getCurrentRole() == Player.Role.MID_BLOCKER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontRightLoc.x  += 85;
                                player.setPlayerLocation(frontRightLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.POWER_HITTER && 
                                     teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                frontRightLoc.x  += 90;
                                frontRightLoc.y  -= 100;
                                player.setPlayerLocation(frontRightLoc);
                            }
                            else if( teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE &&
                                     getPlayer(Player.Position.BACK_RIGHT).getCurrentRole() == Player.Role.SETTER ) {
                                frontRightLoc.x  += 100;
                                player.setPlayerLocation(frontRightLoc);
                            }
                            else if( teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                if (getPlayer(Player.Position.BACK_CENTER).getCurrentRole() == Player.Role.SETTER) {
                                    frontRightLoc.x  -= 50; }
                                else { frontRightLoc.x  -= 150; }
                                player.setPlayerLocation(frontRightLoc);
                            }
                            else { player.setPlayerLocation(frontRightLoc); }
                            break;
                        case BACK_CENTER:
                            if( player.getCurrentRole() == Player.Role.SETTER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                backCenterLoc.x  += 50;
                                backCenterLoc.y  += 125;
                                player.setPlayerLocation(backCenterLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.SETTER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                backCenterLoc.x  += 150;
                                player.setPlayerLocation(backCenterLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.DEFENDER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                if (getPlayer(Player.Position.BACK_LEFT).getCurrentRole() == Player.Role.SETTER) {
                                    backCenterLoc.x  -= 50;
                                    backCenterLoc.y  -= 150;
                                }
                                else if (getPlayer(Player.Position.BACK_RIGHT).getCurrentRole() == Player.Role.SETTER) {
                                    backCenterLoc.x  -= 50;
                                    backCenterLoc.y  += 150;
                                }
                                player.setPlayerLocation(backCenterLoc);
                            }
                            else { player.setPlayerLocation(backCenterLoc); }
                            break;
                        case BACK_LEFT: 
                            if( player.getCurrentRole() == Player.Role.SETTER && 
                                teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE ) {
                                backLeftLoc.x  += 150;
                                backLeftLoc.y  += 40;
                                player.setPlayerLocation(backLeftLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.SETTER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                backLeftLoc.x  += 250;
                                player.setPlayerLocation(backLeftLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.DEFENDER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                if (getPlayer(Player.Position.BACK_CENTER).getCurrentRole() == Player.Role.SETTER) {
                                    backLeftLoc.y  += 50;
                                } else {
                                    backLeftLoc.x  -= 50;
                                    backLeftLoc.y  += 125;
                                }
                                player.setPlayerLocation(backLeftLoc);
                            }
                            else { player.setPlayerLocation(backLeftLoc); }
                            break;
                        case BACK_RIGHT:
                            if ( teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE) {
                                 player.setPlayerLocation(SERVER_DEFAULT_LOCATION );
                            }
                            else if( player.getCurrentRole() == Player.Role.SETTER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                backRightLoc.x  += 275;
                                player.setPlayerLocation(backRightLoc);
                            }
                            else if( player.getCurrentRole() == Player.Role.DEFENDER && 
                                     teamStartingFormation == StartingFormation.FORMATION_RECEIVE_SERVE ) {
                                if (getPlayer(Player.Position.BACK_CENTER).getCurrentRole() == Player.Role.SETTER) {
                                    backRightLoc.y  -= 50; }
                                else { 
                                    backRightLoc.x  -= 25;
                                    backRightLoc.y  -= 150; 
                                }
                                player.setPlayerLocation(backRightLoc);
                            }
                            break;
                        default:  break;
                    }
                }
            } // end else if (teamFormation == Formation.FORMATION_6_2)

        } // end movePlayersStartingFormation
        
        /** rotatePlayers */
        public void rotatePlayers(){
            // reset team starting formation
            teamStartingFormation = StartingFormation.NO_FORMATION;
            
            // set new positions
            for (Player player : players) {
                switch(player.getPosition())
                {
                    case FRONT_LEFT: 
                        player.setPosition(Player.Position.FRONT_CENTER);
                        player.setPlayerLocation(FRONT_CENTER_DEFAULT_LOCATION);
                        break;
                    case FRONT_CENTER: 
                        player.setPosition(Player.Position.FRONT_RIGHT);
                        player.setPlayerLocation(FRONT_RIGHT_DEFAULT_LOCATION);
                        break;
                    case FRONT_RIGHT: 
                        player.setPosition(Player.Position.BACK_RIGHT);
                        if (teamStartingFormation == StartingFormation.FORMATION_TEAM_SERVE) {
                            player.setPlayerLocation(SERVER_DEFAULT_LOCATION);
                        } else {
                            player.setPlayerLocation(BACK_RIGHT_DEFAULT_LOCATION);
                        }
                        break;
                    case BACK_RIGHT: 
                        player.setPosition(Player.Position.BACK_CENTER);
                        player.setPlayerLocation(BACK_CENTER_DEFAULT_LOCATION);
                        break;
                    case BACK_CENTER: 
                        player.setPosition(Player.Position.BACK_LEFT);
                        player.setPlayerLocation(BACK_LEFT_DEFAULT_LOCATION);
                        break;
                    case BACK_LEFT: 
                        player.setPosition(Player.Position.FRONT_LEFT);
                        player.setPlayerLocation(FRONT_LEFT_DEFAULT_LOCATION);
                        break;
                    default:  break;
                }
            }
        }
        
        // ignore for now
        /*public void mousePressed(MouseEvent e) {}
        public void mouseReleased(MouseEvent e) {}
        public void mouseEntered(MouseEvent e) {}
        public void mouseExited(MouseEvent e) {}
        public void mouseClicked(MouseEvent e) {}
        public void mouseDragged(MouseEvent e) {}
        public void mouseMoved(MouseEvent e) {}*/
} //end Court class